﻿using System.Collections;
using System.ComponentModel;
using System.Windows;
using Creventive.Wpf.ShellFactory.Workspace.Primitives;

namespace Creventive.Wpf.ShellFactory.Workspace
{
    /// <summary>
    ///   Represents a workspace which presents a single view.
    /// </summary>
    public class SingleViewWorkspace : Primitives.Workspace
    {
        #region Static Fields/Constants

        /// <summary>
        /// Backing field for the Source dependency property
        /// </summary>
        public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(IApplicationViewSource), typeof(SingleViewWorkspace), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, (s, e) => ((SingleViewWorkspace)s).OnSourceChanged((IApplicationViewSource)e.OldValue, (IApplicationViewSource)e.NewValue)));

        private static readonly DependencyPropertyKey ActiveWorkspaceItemPropertyKey = DependencyProperty.RegisterReadOnly("ActiveWorkspaceItem", typeof(WorkspaceItem), typeof(SingleViewWorkspace), new UIPropertyMetadata(null, (s, e) => ((SingleViewWorkspace)s).OnActiveWorkspaceItemChanged((WorkspaceItem)e.OldValue, (WorkspaceItem)e.NewValue)));

        /// <summary>
        /// Backing field for the ActiveWorkspaceItem dependency property
        /// </summary>
        public static readonly DependencyProperty ActiveWorkspaceItemProperty = ActiveWorkspaceItemPropertyKey.DependencyProperty;

        #endregion

        static SingleViewWorkspace()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SingleViewWorkspace), new FrameworkPropertyMetadata(typeof(SingleViewWorkspace)));
        }

        /// <summary>
        ///   Gets the currently active workspace item.
        /// </summary>
        /// <value>The active workspace item.</value>
        public WorkspaceItem ActiveWorkspaceItem
        {
            get { return (WorkspaceItem)this.GetValue(ActiveWorkspaceItemProperty); }
            private set { this.SetValue(ActiveWorkspaceItemPropertyKey, value); }
        }

        /// <summary>
        ///   Gets an enumerator for logical child elements of this element.
        /// </summary>
        /// <value></value>
        /// <returns>An enumerator for logical child elements of this element.</returns>
        protected override sealed IEnumerator LogicalChildren
        {
            get
            {
                var item = this.ActiveWorkspaceItem;
                if (item != null)
                    yield return item;
            }
        }

        /// <summary>
        ///   Gets or sets the reference to the view to present.
        /// </summary>
        /// <value>The source.</value>
        [TypeConverter(typeof(ApplicationViewSourceConverter))]
        public IApplicationViewSource Source
        {
            get { return (IApplicationViewSource)this.GetValue(SourceProperty); }
            set { this.SetValue(SourceProperty, value); }
        }

        /// <summary>
        ///   Called when the active workspace item has changed.
        /// </summary>
        /// <param name = "oldItem">The old item.</param>
        /// <param name = "newItem">The new item.</param>
        protected virtual void OnActiveWorkspaceItemChanged(WorkspaceItem oldItem, WorkspaceItem newItem)
        {
            if (oldItem == newItem)
                return;

            if (oldItem != null)
            {
                WorkspaceHelper.NotifyDeactivated(oldItem);
                this.Close(oldItem.ApplicationView, ApplicationViewClosingMode.NoQuery);
                this.RemoveLogicalChild(oldItem);
            }
            if (newItem != null)
            {
                this.AddLogicalChild(newItem);
                WorkspaceHelper.NotifyActivated(newItem);
            }
        }

        /// <summary>
        ///   Called when the Source property has changed.
        /// </summary>
        /// <param name = "oldValue">The old value.</param>
        /// <param name = "newValue">The new value.</param>
        protected virtual void OnSourceChanged(IApplicationViewSource oldValue, IApplicationViewSource newValue)
        {
            this.Open(newValue);
        }

        /// <summary>
        ///   Determines whether the specified application view exists within this workspace.
        /// </summary>
        /// <param name = "applicationView">The application view.</param>
        /// <returns>
        ///   <c>true</c> if the specified application view contains view; otherwise, <c>false</c>.
        /// </returns>
        public override bool ContainsView(ApplicationView applicationView)
        {
            return (this.ActiveWorkspaceItem != null && ReferenceEquals(this.ActiveWorkspaceItem, applicationView));
        }

        /// <summary>
        ///   Called when the ContainerStyle property has changed.
        /// </summary>
        /// <param name = "oldValue">The old value.</param>
        /// <param name = "newValue">The new value.</param>
        protected override void OnContainerStyleChanged(Style oldValue, Style newValue)
        {
            if (this.ActiveWorkspaceItem != null)
            {
                if (oldValue != null && newValue == null)
                    this.ActiveWorkspaceItem.ClearValue(StyleProperty);
                else
                    this.ActiveWorkspaceItem.Style = newValue;
            }
        }

        /// <summary>
        ///   Called when a view should be activated.
        /// </summary>
        /// <param name = "view">The view.</param>
        protected override void OnActivateView(ApplicationView view)
        {
            // Since this workspace only support a single view it will always be active.
        }

        /// <summary>
        /// Called when a new view has been added to the workspace.
        /// </summary>
        /// <param name="view">The view.</param>
        protected override void OnAddView(ApplicationView view)
        {
            // Create the view's workspace item
            var workspaceItem = this.CreateItem(view);

            // Set the view as the current view
            this.ActiveWorkspaceItem = workspaceItem;
        }

        /// <summary>
        /// Called when a view is to be removed from the workspace.
        /// </summary>
        /// <param name="view">The view.</param>
        protected override void OnRemoveView(ApplicationView view)
        {
            if (this.ActiveWorkspaceItem != null && ReferenceEquals(this.ActiveWorkspaceItem.ApplicationView, view))
            {
                // Find the view's workspace item
                var workspaceItem = this.CreateItem(view);

                // Reset the active workspace item
                this.ClearValue(ActiveWorkspaceItemPropertyKey);

                // Finally destroy the workspace item.
                this.DestroyItem(workspaceItem);
            }
        }
    }
}